package com.spark.gaea.data.mybatis.interceptor;

import com.spark.gaea.data.mybatis.DataPermissionsBacked;
import com.spark.gaea.security.utils.SessionUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.sql.Connection;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class})})
public class SqlStatementInterceptor implements Interceptor {
	private static final Logger logger;

	final Pattern p = Pattern.compile("<val>(\\w+)</val>");

	@Autowired
	private DataPermissionsBacked dataPermissionsBacked;

	@Override
	public Object intercept(final Invocation arg0) {
		final StatementHandler statementHandler = (StatementHandler) arg0.getTarget();
		final MetaObject metaStatementHandler = SystemMetaObject.forObject(statementHandler);
		try {
			final MappedStatement mappedStatement = (MappedStatement) metaStatementHandler.getValue("delegate.mappedStatement");
			final String sqlId = mappedStatement.getId();
			final BoundSql boundSql = (BoundSql) metaStatementHandler.getValue("delegate.boundSql");
			String sql = boundSql.getSql();
			if (StringUtils.isBlank(sql) || StringUtils.isBlank(sqlId)) {
				return arg0.proceed();
			}
			SqlStatementInterceptor.logger.trace("原始SQL语句 >>>>>> \n" + sql);
			if (sql.indexOf("#?") >= 0) {
				final String replaceSql = this.getsql(sqlId);
				if (replaceSql == null) {
					sql = sql.replace("#?", "");
				} else {
					sql = sql.replace("#?", replaceSql);
				}
				metaStatementHandler.setValue("delegate.boundSql.sql", sql);
			}
			SqlStatementInterceptor.logger.trace("转换后SQL语句 >>>>>> \n" + sql);
			final Object returnValue = arg0.proceed();
			return returnValue;
		} catch (Exception e) {
			SqlStatementInterceptor.logger.info("数据权限sql拼接异常！！");
			SqlStatementInterceptor.logger.error(e.getMessage());
			return null;
		}
	}

	private String getsql(final String sqlId) {
		String result = null;
		try {
			final Set<Map<String, String>> list = this.dataPermissionsBacked
					.getSqlParameterList(SessionUtil.getUserId(), sqlId);
			if (list.size() > 0) {
				final StringBuilder querySql = new StringBuilder();
				querySql.append("and (");
				querySql.append("(1=1)");
				for (final Map ss : list) {
					final String sqlStr = this.setSqlparameter(ss);
					if (sqlStr != null) {
						querySql.append("and (").append(sqlStr).append(")");
					}
				}
				querySql.append(")");
				result = querySql.toString();
			}
			SqlStatementInterceptor.logger.info("\u62fc\u63a5\u6761\u4ef6:" + result);
		} catch (Exception e) {
			SqlStatementInterceptor.logger.error(e.getMessage());
		}
		return result;
	}

	private String setSqlparameter(final Map ss) {
		try {
			if (ss != null && !ss.isEmpty()) {
				String sqlStr = ss.get("sqlPar").toString();
				if (sqlStr.contains("<val>") && sqlStr.contains("</val>")) {

					final Matcher m = p.matcher(sqlStr);
					while (m.find()) {
						final String insertKey = m.group(1);
						final String insertValue = SessionUtil.get(insertKey).toString();
						sqlStr = sqlStr.replace("<val>" + insertKey + "</val>", insertValue);
						SqlStatementInterceptor.logger
								.info("\u63d2\u5165\u503cKey:" + insertKey + " \uff0c\u63d2\u5165\u503cValue:"
										+ insertValue);
					}
				}
				return sqlStr;
			}
		} catch (Exception e) {
			SqlStatementInterceptor.logger.info("session\u503c\u83b7\u53d6\u5f02\u5e38:" + ss.get("sqlPar"));
			return null;
		}
		return null;
	}

	@Override
	public Object plugin(final Object target) {
		if (target instanceof StatementHandler) {
			return Plugin.wrap(target, this);
		}
		return target;
	}

	@Override
	public void setProperties(final Properties arg0) {
		Properties properties = arg0;
	}

	static {
		logger = LoggerFactory.getLogger(SqlStatementInterceptor.class);
	}
}
